package com.hulk.ratel.config.pool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 注意：该线程池被所有的异步任务共享，而不属于某一个异步任务
 * 描述：配置异步任务的线程池
 * @author cmt
 * 创建时间：2017年5月22日 上午10:20:56
 * @version 1.2.0
 */
@Slf4j
@Configuration
@EnableAsync
public class AsyncTaskExecutePool implements AsyncConfigurer{

	/** Set the ThreadPoolExecutor's core pool size. */
	private int corePoolSize = 5;
	/** Set the ThreadPoolExecutor's maximum pool size. */
	private int maxPoolSize = 20;
	/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
	private int queueCapacity = 10;



	@Override
    public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        //executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
        executor.setThreadNamePrefix("asyncConfigurer-");
  
        // rejection-policy：当pool已经达到max size的时候，如何处理新任务  
        // CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行  
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();  
        return executor;  
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {// 异步任务中异常处理
		return new AsyncUncaughtExceptionHandler() {

			@Override
			public void handleUncaughtException(Throwable ex, Method arg1, Object... arg2) {
				if (ex instanceof RuntimeException) {
					RuntimeException asyncException = (RuntimeException) ex;
					log.error("asyncException:{},exception method:{}",asyncException.getMessage(),arg1.getName());
					for (Object param : arg2) {
						log.info("Parameter value - " + param);
					}
				}else {
					log.error("ex:{},exception method:{}",ex.getMessage(),arg1.getName());
					for (Object param : arg2) {
						log.info("Parameter value - " + param);
					}
				}

			}
		};
	}  
}